home *** CD-ROM | disk | FTP | other *** search
/ AI Game Programming Wisdom / AIGameProgrammingWisdom.iso / SourceCode / 11 Learning / 04 Mommersteeg / Tennis / SoundBuffer.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-09-23  |  17.4 KB  |  562 lines

  1. //----------------------------------------------------------------------------------------------
  2. // Sequential Prediction Demo: The positioning pattern
  3. // 
  4. // Author:  Fri Mommersteeg
  5. // Date:    10-09-2001
  6. // File:    SoundBuffer.h
  7. //----------------------------------------------------------------------------------------------
  8.  
  9. //----------------------------------------------------------------------------------------------
  10. // Include files
  11. //----------------------------------------------------------------------------------------------
  12.  
  13. #include "StdAfx.h"
  14. #include "SoundBuffer.h"
  15.  
  16. //----------------------------------------------------------------------------------------------
  17. // CSoundBuffer(): constructor
  18. //----------------------------------------------------------------------------------------------
  19.  
  20. CSoundBuffer::CSoundBuffer()
  21. {
  22.     lpDS = NULL;
  23.     lpDSB = NULL;
  24. }
  25.  
  26. //----------------------------------------------------------------------------------------------
  27. // ~CSoundBuffer(): destructor
  28. //----------------------------------------------------------------------------------------------
  29.  
  30. CSoundBuffer::~CSoundBuffer()
  31. {
  32.     Release();
  33. }
  34.  
  35. //----------------------------------------------------------------------------------------------
  36. // CSoundBuffer(): creates a new soundbuffer according the specified requirements
  37. //----------------------------------------------------------------------------------------------
  38.  
  39. void CSoundBuffer::Create(LPDS lpds, DWORD dwBufferSize, DWORD dwFrequency, WORD nChannels, WORD wBitsPerSample, DWORD dwFlags )
  40. {
  41.     lpDS = lpds;
  42.  
  43.     DSBD dsbd;
  44.     WAVEFORMATEX wfx;
  45.  
  46.     // set up wave format
  47.     wfx.wFormatTag = WAVE_FORMAT_PCM;
  48.     wfx.nChannels = nChannels;
  49.     wfx.nSamplesPerSec = dwFrequency;
  50.     wfx.wBitsPerSample = wBitsPerSample;
  51.     wfx.nBlockAlign = nChannels * wBitsPerSample / 8;
  52.     wfx.nAvgBytesPerSec = dwFrequency * wfx.nBlockAlign;
  53.     wfx.cbSize = 0;
  54.  
  55.     // set up sound buffer description
  56.     ZeroMemory(&dsbd, sizeof(dsbd));
  57.     dsbd.dwSize = sizeof(dsbd);
  58.     dsbd.dwFlags = dwFlags | DSBCAPS_STATIC;
  59.     dsbd.dwBufferBytes = dwBufferSize;
  60.     dsbd.lpwfxFormat = &wfx;
  61.  
  62.     // create sound buffer
  63.     lpDS->CreateSoundBuffer(&dsbd, &lpDSB, NULL);
  64.  
  65.     // fill sound buffer with silence
  66.     Silence();
  67. }
  68.  
  69. //----------------------------------------------------------------------------------------------
  70. // CSoundBuffer(): creates a new soundbuffer using the specified wave file
  71. //----------------------------------------------------------------------------------------------
  72.  
  73. void CSoundBuffer::CreateWave(LPDS lpds, LPSTR strWave, DWORD dwFlags)
  74. {
  75.     lpDS = lpds;
  76.  
  77.     DSBD    dsbd;
  78.     LPVOID    lpvAudio;
  79.     DWORD    dwBytes;
  80.     UINT    cbBytesRead;
  81.  
  82.     // open file for input
  83.     WaveOpenFile( strWave, &hmmio, &pwfx, &mmckinfoParent );
  84.  
  85.     // prepare file for input
  86.     WaveStartDataRead( &hmmio, &mmckinfo, &mmckinfoParent );
  87.  
  88.     // set up buffer description
  89.     ZeroMemory(&dsbd, sizeof(dsbd));
  90.     dsbd.dwSize = sizeof(dsbd);
  91.     dsbd.dwFlags = dwFlags | DSBCAPS_STATIC;
  92.     dsbd.dwBufferBytes = mmckinfo.cksize;
  93.     dsbd.lpwfxFormat = pwfx;
  94.  
  95.     // create sound buffer
  96.     lpDS->CreateSoundBuffer(&dsbd, &lpDSB, NULL);
  97.  
  98.     // read wave data into buffer
  99.     lpDSB->Lock(0, 0, &lpvAudio, &dwBytes, NULL, NULL, DSBLOCK_ENTIREBUFFER);
  100.     WaveReadFile( hmmio, dwBytes, (BYTE *)lpvAudio, &mmckinfo, &cbBytesRead );
  101.     lpDSB->Unlock( lpvAudio, dwBytes, NULL, 0);
  102.  
  103.     // close file
  104.     WaveCloseReadFile( &hmmio, &pwfx );
  105. }
  106.  
  107. //----------------------------------------------------------------------------------------------
  108. // CreateCopy(): creates a reference copy of the sound buffer
  109. //----------------------------------------------------------------------------------------------
  110.  
  111. void CSoundBuffer::CreateCopy(LPDS lpds, LPDSB lpDSB)
  112. {
  113.     lpDS = lpds;
  114.     lpDSB = lpDSB;
  115. }
  116.  
  117. //----------------------------------------------------------------------------------------------
  118. // CreateDuplicate(): creates a duplicate of the sound buffer
  119. //----------------------------------------------------------------------------------------------
  120.  
  121. void CSoundBuffer::CreateDuplicate(LPDS lpds, LPDSB lpDSB)
  122. {
  123.     lpDS = lpds;
  124.     lpDS->DuplicateSoundBuffer(lpDSB, &this->lpDSB);
  125. }
  126.  
  127. //----------------------------------------------------------------------------------------------
  128. // Release(): releases the sound buffer
  129. //----------------------------------------------------------------------------------------------
  130.  
  131. void CSoundBuffer::Release()
  132. {
  133.     if ( lpDSB != NULL )
  134.     {
  135.         lpDSB->Release();
  136.         lpDSB = NULL;
  137.     }
  138.     lpDS = NULL;
  139. }
  140.  
  141. //----------------------------------------------------------------------------------------------
  142. // ReleaseCopy(): releases a copy of the sound buffer
  143. //----------------------------------------------------------------------------------------------
  144.  
  145. void CSoundBuffer::ReleaseCopy()
  146. {
  147.     lpDSB = NULL;
  148.     lpDS = NULL;
  149. }
  150.  
  151. //----------------------------------------------------------------------------------------------
  152. // Play(): plays the soundbuffer
  153. //----------------------------------------------------------------------------------------------
  154.  
  155. void CSoundBuffer::Play(BOOL bLooping)
  156. {
  157.     HRESULT hr = lpDSB->Play(0, 0, bLooping ? DSBPLAY_LOOPING : 0);
  158.  
  159.     if ( FAILED( hr ) )
  160.     {
  161.         if ( hr == DSERR_BUFFERLOST )
  162.         {
  163.             // restore buffer and resume
  164.             lpDSB->Restore();
  165.             lpDSB->Play(0, 0, bLooping ? DSBPLAY_LOOPING : 0);
  166.         }
  167.     }
  168. }
  169.  
  170. //----------------------------------------------------------------------------------------------
  171. // Stop(): stops a playing sound buffer
  172. //----------------------------------------------------------------------------------------------
  173.  
  174. void CSoundBuffer::Stop()
  175. {
  176.     lpDSB->Stop();
  177. }
  178.  
  179. //----------------------------------------------------------------------------------------------
  180. // Silence(): fills a sound buffer with silence
  181. //----------------------------------------------------------------------------------------------
  182.  
  183. void CSoundBuffer::Silence()
  184. {
  185.     WAVEFORMATEX    wfx;
  186.     DWORD           dwSizeWritten;
  187.     PBYTE            pb;
  188.     DWORD            cb;
  189.  
  190.     lpDSB->GetFormat( &wfx, sizeof( WAVEFORMATEX ), &dwSizeWritten );
  191.  
  192.     lpDSB->Lock( 0, 0, (LPVOID *)&pb, &cb, NULL, NULL, DSBLOCK_ENTIREBUFFER );
  193.     FillMemory( pb, cb, ( wfx.wBitsPerSample == 8 ) ? 128 : 0 );
  194.     lpDSB->Unlock( pb, cb, NULL, 0 );
  195. }
  196.  
  197. //----------------------------------------------------------------------------------------------
  198. // WaveOpenFile(): This function will open a wave input file and prepare it for reading, so the 
  199. // data can be easily read with WaveReadFile. Returns 0 if successful, the error code if not.
  200. //
  201. //      pszFileName - Input filename to load.
  202. //      phmmioIn    - Pointer to handle which will be used for further mmio routines.
  203. //      ppwfxInfo   - Ptr to ptr to WaveFormatEx structure with all info about the file.
  204. //----------------------------------------------------------------------------------------------
  205.  
  206. int CSoundBuffer::WaveOpenFile(
  207.     TCHAR*pszFileName,                              // (IN)
  208.     HMMIO *phmmioIn,                                // (OUT)
  209.     WAVEFORMATEX **ppwfxInfo,                       // (OUT)
  210.     MMCKINFO *pckInRIFF                             // (OUT)
  211.             )
  212. {
  213.     HMMIO           hmmioIn;
  214.     MMCKINFO        ckIn;           // chunk info. for general use.
  215.     PCMWAVEFORMAT   pcmWaveFormat;  // Temp PCM structure to load in.
  216.     WORD            cbExtraAlloc;   // Extra bytes for waveformatex
  217.     int             nError;         // Return value.
  218.  
  219.  
  220.     // Initialization...
  221.     *ppwfxInfo = NULL;
  222.     nError = 0;
  223.     hmmioIn = NULL;
  224.  
  225.     if ((hmmioIn = mmioOpen(pszFileName, NULL, MMIO_ALLOCBUF | MMIO_READ)) == NULL)
  226.         {
  227.         nError = ER_CANNOTOPEN;
  228.         goto ERROR_READING_WAVE;
  229.         }
  230.  
  231.     if ((nError = (int)mmioDescend(hmmioIn, pckInRIFF, NULL, 0)) != 0)
  232.         {
  233.         goto ERROR_READING_WAVE;
  234.         }
  235.  
  236.  
  237.     if ((pckInRIFF->ckid != FOURCC_RIFF) || (pckInRIFF->fccType != mmioFOURCC('W', 'A', 'V', 'E')))
  238.         {
  239.         nError = ER_NOTWAVEFILE;
  240.         goto ERROR_READING_WAVE;
  241.         }
  242.  
  243.     /* Search the input file for for the 'fmt ' chunk.     */
  244.     ckIn.ckid = mmioFOURCC('f', 'm', 't', ' ');
  245.     if ((nError = (int)mmioDescend(hmmioIn, &ckIn, pckInRIFF, MMIO_FINDCHUNK)) != 0)
  246.         {
  247.         goto ERROR_READING_WAVE;
  248.         }
  249.  
  250.     /* Expect the 'fmt' chunk to be at least as large as <PCMWAVEFORMAT>;
  251.     * if there are extra parameters at the end, we'll ignore them */
  252.  
  253.     if (ckIn.cksize < (long) sizeof(PCMWAVEFORMAT))
  254.         {
  255.         nError = ER_NOTWAVEFILE;
  256.         goto ERROR_READING_WAVE;
  257.         }
  258.  
  259.     /* Read the 'fmt ' chunk into <pcmWaveFormat>.*/
  260.     if (mmioRead(hmmioIn, (HPSTR) &pcmWaveFormat, (long) sizeof(pcmWaveFormat)) != (long) sizeof(pcmWaveFormat))
  261.         {
  262.         nError = ER_CANNOTREAD;
  263.         goto ERROR_READING_WAVE;
  264.         }
  265.  
  266.  
  267.     // Ok, allocate the waveformatex, but if its not pcm
  268.     // format, read the next word, and thats how many extra
  269.     // bytes to allocate.
  270.     if (pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_PCM)
  271.         cbExtraAlloc = 0;
  272.  
  273.     else
  274.         {
  275.         // Read in length of extra bytes.
  276.         if (mmioRead(hmmioIn, (LPTSTR) &cbExtraAlloc,
  277.             (long) sizeof(cbExtraAlloc)) != (long) sizeof(cbExtraAlloc))
  278.             {
  279.             nError = ER_CANNOTREAD;
  280.             goto ERROR_READING_WAVE;
  281.             }
  282.  
  283.         }
  284.  
  285.     // Ok, now allocate that waveformatex structure.
  286.     if ((*ppwfxInfo = (WAVEFORMATEX *)GlobalAlloc(GMEM_FIXED, sizeof(WAVEFORMATEX)+cbExtraAlloc)) == NULL)
  287.         {
  288.         nError = ER_MEM;
  289.         goto ERROR_READING_WAVE;
  290.         }
  291.  
  292.     // Copy the bytes from the pcm structure to the waveformatex structure
  293.     memcpy(*ppwfxInfo, &pcmWaveFormat, sizeof(pcmWaveFormat));
  294.     (*ppwfxInfo)->cbSize = cbExtraAlloc;
  295.  
  296.     // Now, read those extra bytes into the structure, if cbExtraAlloc != 0.
  297.     if (cbExtraAlloc != 0)
  298.         {
  299.         if (mmioRead(hmmioIn, (LPTSTR) (((BYTE*)&((*ppwfxInfo)->cbSize))+sizeof(cbExtraAlloc)),
  300.             (long) (cbExtraAlloc)) != (long) (cbExtraAlloc))
  301.             {
  302.             nError = ER_NOTWAVEFILE;
  303.             goto ERROR_READING_WAVE;
  304.             }
  305.         }
  306.  
  307.     /* Ascend the input file out of the 'fmt ' chunk. */
  308.     if ((nError = mmioAscend(hmmioIn, &ckIn, 0)) != 0)
  309.         {
  310.         goto ERROR_READING_WAVE;
  311.  
  312.         }
  313.  
  314.  
  315.     goto TEMPCLEANUP;
  316.  
  317. ERROR_READING_WAVE:
  318.     if (*ppwfxInfo != NULL)
  319.         {
  320.         GlobalFree(*ppwfxInfo);
  321.         *ppwfxInfo = NULL;
  322.         }
  323.  
  324.     if (hmmioIn != NULL)
  325.     {
  326.     mmioClose(hmmioIn, 0);
  327.         hmmioIn = NULL;
  328.         }
  329.  
  330. TEMPCLEANUP:
  331.     *phmmioIn = hmmioIn;
  332.  
  333.     return(nError);
  334.  
  335. }
  336.  
  337. //----------------------------------------------------------------------------------------------
  338. // WaveStartDataRead(): This routine has to be called before WaveReadFile as it searchs for the 
  339. // chunk to descend into for reading, that is, the 'data' chunk.  For simplicity, this used to 
  340. // be in the open routine, but was taken out and moved to a separate routine so there was more 
  341. // control on the chunks that are before the data chunk, such as 'fact', etc...
  342. //----------------------------------------------------------------------------------------------
  343.  
  344. int CSoundBuffer::WaveStartDataRead(
  345.                     HMMIO *phmmioIn,
  346.                     MMCKINFO *pckIn,
  347.                     MMCKINFO *pckInRIFF
  348.                     )
  349. {
  350.     int                     nError;
  351.  
  352.     nError = 0;
  353.  
  354.     // Do a nice little seek...
  355.     if ((nError = mmioSeek(*phmmioIn, pckInRIFF->dwDataOffset + sizeof(FOURCC), SEEK_SET)) == -1)
  356.         {
  357.         _ASSERT(FALSE);
  358.         }
  359.  
  360.     nError = 0;
  361.     //      Search the input file for for the 'data' chunk.
  362.     pckIn->ckid = mmioFOURCC('d', 'a', 't', 'a');
  363.     if ((nError = mmioDescend(*phmmioIn, pckIn, pckInRIFF, MMIO_FINDCHUNK)) != 0)
  364.         {
  365.         goto ERROR_READING_WAVE;
  366.         }
  367.  
  368.     goto CLEANUP;
  369.  
  370. ERROR_READING_WAVE:
  371.  
  372. CLEANUP:
  373.     return(nError);
  374. }
  375.  
  376. //----------------------------------------------------------------------------------------------
  377. // WaveFileRad(): This will read wave data from the wave file. Make sure we're descended into
  378. // the data chunk, else this will fail bigtime!
  379. //
  380. //  hmmioIn         - Handle to mmio.
  381. //  cbRead          - # of bytes to read.
  382. //  pbDest          - Destination buffer to put bytes.
  383. //  cbActualRead- # of bytes actually read.
  384. //----------------------------------------------------------------------------------------------
  385.  
  386. int CSoundBuffer::WaveReadFile(
  387.         HMMIO hmmioIn,                          // IN
  388.         UINT cbRead,                            // IN
  389.         BYTE *pbDest,                           // IN
  390.         MMCKINFO *pckIn,                        // IN.
  391.         UINT *cbActualRead                      // OUT.
  392.  
  393.         )
  394. {
  395.  
  396.     MMIOINFO    mmioinfoIn;         // current status of <hmmioIn>
  397.     int                     nError;
  398.     UINT            cT, cbDataIn;
  399.  
  400.     nError = 0;
  401.  
  402.     if (nError = mmioGetInfo(hmmioIn, &mmioinfoIn, 0) != 0)
  403.         {
  404.         goto ERROR_CANNOT_READ;
  405.         }
  406.  
  407.     cbDataIn = cbRead;
  408.     if (cbDataIn > pckIn->cksize)
  409.         cbDataIn = pckIn->cksize;
  410.  
  411.     pckIn->cksize -= cbDataIn;
  412.  
  413.     for (cT = 0; cT < cbDataIn; cT++)
  414.         {
  415.         /* Copy the bytes from the io to the buffer. */
  416.         if (mmioinfoIn.pchNext == mmioinfoIn.pchEndRead)
  417.             {
  418.         if ((nError = mmioAdvance(hmmioIn, &mmioinfoIn, MMIO_READ)) != 0)
  419.                 {
  420.         goto ERROR_CANNOT_READ;
  421.                 }
  422.         if (mmioinfoIn.pchNext == mmioinfoIn.pchEndRead)
  423.                 {
  424.                 nError = ER_CORRUPTWAVEFILE;
  425.         goto ERROR_CANNOT_READ;
  426.                 }
  427.             }
  428.  
  429.         // Actual copy. Transform.
  430.         *((BYTE*)pbDest+cT) = *((BYTE*)mmioinfoIn.pchNext);
  431.         mmioinfoIn.pchNext = ((char *)mmioinfoIn.pchNext+1);
  432.         }
  433.  
  434.     if ((nError = mmioSetInfo(hmmioIn, &mmioinfoIn, 0)) != 0)
  435.         {
  436.         goto ERROR_CANNOT_READ;
  437.         }
  438.  
  439.     *cbActualRead = cbDataIn;
  440.     goto FINISHED_READING;
  441.  
  442. ERROR_CANNOT_READ:
  443.     *cbActualRead = 0;
  444.  
  445. FINISHED_READING:
  446.     return(nError);
  447.  
  448. }
  449.  
  450.  
  451. //----------------------------------------------------------------------------------------------
  452. // WaveCloseReadFile(): This will close the wave file opened with WaveOpenFile.
  453. //    phmmioIn - Pointer to the handle to input MMIO.
  454. //    ppwfxSrc - Pointer to pointer to WaveFormatEx structure.
  455. //
  456. //    Returns 0 if successful, non-zero if there was a warning.
  457. //----------------------------------------------------------------------------------------------
  458.  
  459. int CSoundBuffer::WaveCloseReadFile(
  460.             HMMIO *phmmio,                          // IN
  461.             WAVEFORMATEX **ppwfxSrc                 // IN
  462.             )
  463. {
  464.  
  465.     if (*ppwfxSrc != NULL)
  466.         {
  467.         GlobalFree(*ppwfxSrc);
  468.         *ppwfxSrc = NULL;
  469.         }
  470.  
  471.     if (*phmmio != NULL)
  472.         {
  473.         mmioClose(*phmmio, 0);
  474.         *phmmio = NULL;
  475.         }
  476.  
  477.     return(0);
  478.  
  479. }
  480.  
  481. //----------------------------------------------------------------------------------------------
  482. // WaveLoadFile(): This routine loads a full wave file into memory. Be careful, wave files can 
  483. // get pretty big these days :).
  484. //
  485. //    szFileName      -       sz Filename
  486. //    cbSize          -       Size of loaded wave (returned)
  487. //    cSamples        -       # of samples loaded.
  488. //    ppwfxInfo       -       Pointer to pointer to waveformatex structure. The wfx structure 
  489. //                              IS ALLOCATED by this routine!  Make sure to free it!
  490. //    ppbData         -       Pointer to a byte pointer (globalalloc) which is allocated by this
  491. //                              routine.  Make sure to free it!
  492. //
  493. //    Returns 0 if successful, else the error code.
  494. //----------------------------------------------------------------------------------------------
  495.  
  496. int CSoundBuffer::WaveLoadFile(
  497.             TCHAR*pszFileName,                      // (IN)
  498.             UINT *cbSize,                           // (OUT)
  499.             WAVEFORMATEX **ppwfxInfo,                // (OUT)
  500.             BYTE **ppbData                          // (OUT)
  501.             )
  502. {
  503.  
  504.     HMMIO                           hmmioIn;
  505.     MMCKINFO                        ckInRiff;
  506.     MMCKINFO                        ckIn;
  507.     int                                     nError;
  508.     UINT                            cbActualRead;
  509.  
  510.     *ppbData = NULL;
  511.     *ppwfxInfo = NULL;
  512.     *cbSize = 0;
  513.  
  514.     if ((nError = WaveOpenFile(pszFileName, &hmmioIn, ppwfxInfo, &ckInRiff)) != 0)
  515.         {
  516.         goto ERROR_LOADING;
  517.         }
  518.  
  519.     if ((nError = WaveStartDataRead(&hmmioIn, &ckIn, &ckInRiff)) != 0)
  520.         {
  521.         goto ERROR_LOADING;
  522.         }
  523.  
  524.     // Ok, size of wave data is in ckIn, allocate that buffer.
  525.     if ((*ppbData = (BYTE *)GlobalAlloc(GMEM_FIXED, ckIn.cksize)) == NULL)
  526.         {
  527.         nError = ER_MEM;
  528.         goto ERROR_LOADING;
  529.         }
  530.  
  531.     if ((nError = WaveReadFile(hmmioIn, ckIn.cksize, *ppbData, &ckIn, &cbActualRead)) != 0)
  532.         {
  533.         goto ERROR_LOADING;
  534.         }
  535.  
  536.     *cbSize = cbActualRead;
  537.     goto DONE_LOADING;
  538.  
  539. ERROR_LOADING:
  540.     if (*ppbData != NULL)
  541.         {
  542.         GlobalFree(*ppbData);
  543.         *ppbData = NULL;
  544.         }
  545.     if (*ppwfxInfo != NULL)
  546.         {
  547.         GlobalFree(*ppwfxInfo);
  548.         *ppwfxInfo = NULL;
  549.         }
  550.  
  551. DONE_LOADING:
  552.     // Close the wave file.
  553.     if (hmmioIn != NULL)
  554.         {
  555.         mmioClose(hmmioIn, 0);
  556.         hmmioIn = NULL;
  557.         }
  558.  
  559.     return(nError);
  560.  
  561. }
  562.